package com.base.pool;

import android.support.annotation.NonNull;
import android.support.v4.util.Pools;
import android.util.Log;

import java.util.ArrayList;
import java.util.List;

public class FactoryPools {
    private static final String TAG = "FactoryPools";
    private static final int DEFAULT_POOL_SIZE = 20;
    private static final FactoryPools.Resetter<Object> EMPTY_RESETTER = new FactoryPools.Resetter<Object>() {
        @Override
        public void reset(@NonNull Object object) {
            // Do nothing.
        }
    };

    private FactoryPools() {
    }

    /**
     * 返回一个非线程安全的的池，其中包含给定对象创建的类型的对象
     * {@link FactoryPools。给定最大尺寸的工厂}。
     * 如果在调用时{@link Pools . pool #acquire()}池为空，则给定的工厂用于创建新实例。
     *
     * @param <T>对象池将包含的类型。
     */
    @NonNull
    public static <T extends Poolable> Pools.Pool<T> simple(int size, @NonNull FactoryPools.Factory<T> factory) {
        return build(new Pools.SimplePool<T>(size), factory);
    }

    /**
     * 返回一个新的线程安全的，它从不返回{@code null}，并且包含
     * {@link List List}具有给定的最大大小的特定泛型类型。
     * 如果在调用时{@link Pools . pool #acquire()}池为空，则会出现一个新的{@link List}创建。
     *
     * @param <T> {@link List Lists}将包含的对象类型。
     */
    @NonNull
    public static <T extends FactoryPools.Poolable> Pools.Pool<T> threadSafe(int size, @NonNull FactoryPools.Factory<T> factory) {
        return build(new Pools.SynchronizedPool<T>(size), factory);
    }

    /**
     * 返回一个新的{@link池。池}从不返回{@code null}，它包含{@link List Lists}
     * 标准最大尺寸为20的特定泛型类型。
     * 如果在调用{@link Pools . pool #acquire()}时池为空，则会出现一个新的{@link List}创建。
     *
     * @param <T> {@link List Lists}将包含的对象类型。
     */
    @NonNull
    public static <T> Pools.Pool<List<T>> threadSafeList() {
        return threadSafeList(DEFAULT_POOL_SIZE);
    }

    /**
     * 返回一个新的线程安全的{@link池。池}，它从不返回{@code null}，并且包含
     * {@link List List}具有给定的最大大小的特定泛型类型。
     *
     * <p>如果在调用{@link Pools . pool #acquire()}时池为空，则会出现一个新的{@link List}
     * 创建。
     *
     * @param <T> {@link List Lists}将包含的对象类型。
     */
    // Public API.
    @SuppressWarnings("WeakerAccess")
    @NonNull
    public static <T> Pools.Pool<List<T>> threadSafeList(int size) {
        return build(new Pools.SynchronizedPool<List<T>>(size), new FactoryPools.Factory<List<T>>() {
            @NonNull
            @Override
            public List<T> create() {
                return new ArrayList<>();
            }
        }, new FactoryPools.Resetter<List<T>>() {
            @Override
            public void reset(@NonNull List<T> object) {
                object.clear();
            }
        });
    }

    @NonNull
    private static <T extends Poolable> Pools.Pool<T> build(@NonNull Pools.Pool<T> pool,
                                                            @NonNull Factory<T> factory) {
        return build(pool, factory, FactoryPools.<T>emptyResetter());
    }

    @NonNull
    private static <T> Pools.Pool<T> build(@NonNull Pools.Pool<T> pool, @NonNull FactoryPools.Factory<T> factory,
                                           @NonNull FactoryPools.Resetter<T> resetter) {
        return new FactoryPools.FactoryPool<>(pool, factory, resetter);
    }

    @NonNull
    @SuppressWarnings("unchecked")
    private static <T> FactoryPools.Resetter<T> emptyResetter() {
        return (FactoryPools.Resetter<T>) EMPTY_RESETTER;
    }

    /**
     * 创建给定类型的新实例。
     *
     * @param <T>将创建的对象类型。
     */
    public interface Factory<T> {
        T create();
    }

    /**
     * 当对象返回到池中时重置状态。
     *
     * @param <T>要重置的对象类型。
     */
    public interface Resetter<T> {
        void reset(@NonNull T object);
    }

    /**
     * 允许额外的验证来捕获在使用对象时产生的错误对象池。
     */
    public interface Poolable {
        @NonNull
        StateVerifier getVerifier();
    }

    private static final class FactoryPool<T> implements Pools.Pool<T> {
        private final FactoryPools.Factory<T> factory;
        private final FactoryPools.Resetter<T> resetter;
        private final Pools.Pool<T> pool;

        FactoryPool(@NonNull Pools.Pool<T> pool, @NonNull FactoryPools.Factory<T> factory, @NonNull FactoryPools.Resetter<T> resetter) {
            this.pool = pool;
            this.factory = factory;
            this.resetter = resetter;
        }

        @Override
        public T acquire() {
            T result = pool.acquire();
            if (result == null) {
                result = factory.create();
                if (Log.isLoggable(TAG, Log.VERBOSE)) {
                    Log.v(TAG, "Created new " + result.getClass());
                }
            }
            if (result instanceof FactoryPools.Poolable) {
                ((FactoryPools.Poolable) result).getVerifier().setRecycled(false /*isRecycled*/);
            }
            return result;
        }

        @Override
        public boolean release(@NonNull T instance) {
            if (instance instanceof FactoryPools.Poolable) {
                ((FactoryPools.Poolable) instance).getVerifier().setRecycled(true /*isRecycled*/);
            }
            resetter.reset(instance);
            return pool.release(instance);
        }
    }
}
